package com.zp.thread;
/**
 * wait()和notify()的用法：(打印 1 0 1 0 1 0 1 0.....)
 * 
 * wait():使当前线程进入等待状态，这个线程必须拥有这个对象的锁，即wait()
 *        方法在synchronized关键字的方法内或者在synchronized块中，当
 *        调用了wait()方法时，该线程就释放了该锁的拥有权，这时候其他线程
 *        就可以进入含有synchronized关键字的方法中，只有其他线程调用了
 *        notify()方法时才能被唤醒，然后执行后面的方法；
 *        
 * notify():可以唤醒一个线程，在多个等待线程中，被唤醒的线程是哪个不确定；
 *          原因：被唤醒的线程还不能立刻执行，只有当线程放弃了该对象的锁时，
 *          被唤醒的线程还需和其他线程竞争该对象的锁，获得锁之后才能执行；
 *          获得锁的途径：(详见API文档)
 *          
 * 条件一：只有it1和dt1两个线程的，if判断语句：if(0 !=/= number);
 * a)打印结果：(期望结果)
 *   1 0 1 0 1 0 1 0.....
 * b)详解：
 *   由于number初始值为0，it1和dt1执行顺序是不确定的；
 *   假设当dt1执行decrease()方法时，满足0 == number，
 *   则会执行wait()方法，进入等待状态等待其他线程调用
 *   notify()方法来唤醒dt1线程；
 *   然后当it1执行increase()方法时，不满足0 != number，
 *   则会执行number++语句，打印结果为1；此时调用notify()
 *   方法，唤醒某个不确定的线程，因为只有两个线程，所以就
 *   唤醒了等待中的线程dt1，此时number是1(it1执行自增得到的)，
 *   dt1唤醒执行number--;number=0,所以打印结果为0；
 *   （上述过程每个线程循环20遍就得到了上述打印结果）
 *   
 * 条件二：有it1、it2和dt1、dt2四个线程，if判断语句：if(0 !=/= number);
 * a)打印结果：(结果变乱)
 *   1 0 -1 -2 -1 0 1 0 -1 -2 -3.....
 * b)详解：
 *   由于number初始值为0，it1、it2和dt1、dt2执行顺序是不确定的；
 *   假设当dt1、dt2执行decrease()方法时，满足0 == number，
 *   则会执行wait()方法，进入等待状态等待其他线程调用notify()
 *   方法来唤醒dt1、dt2线程；
 *   然后当it1、it2中的一个比如it1执行increase()方法时，
 *   不满足0 != number，则会执行number++语句，打印结果为1；
 *   此时调用notify()方法，唤醒某个不确定的线程，因为只有四个线程，
 *   所以只能唤醒了等待中的线程dt1或dt2，此时number是1(it1自增得到的)，
 *   假如dt1被唤醒后执行number--;number=0,所以打印结果为0；然后dt1再
 *   执行notify()方法，dt2还在等待，若再唤醒了dt2，number=0，则会执行
 *   number--;number=-1;则会打印出-1；所以后面的结果就全部乱了；
 *   （上述过程每个线程循环20遍就得到了上述打印结果）
 * 
 * 思考：若多个线程时，使用if判断会出现混乱结果，主要原因是对number只进行
 *      了一次判断，若每次都判断，则不会出现number=0时，decrease()还继续
 *      执行自减的情况，所以使用while()判断语句就不用担心多个线程会出现结果
 *      混乱的问题了；
 *      
 * 条件三：有it1、it2和dt1、dt2四个线程，while判断语句：while(0 !=/= number);  
 * a)打印结果：(期望结果)
 *   1 0 1 0 1 0 1 0.....
 *  
 * 结论：使用while()判断是最安全的，就不用考虑线程个数问题了；
 */
public class Sample { 
	//int类型的成员变量默认值是0；
	private int number;
	
	public synchronized void increase(){
//		if(0 != number){
		while(0 != number){
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		number++;
		System.out.println(number);
		notify();
	}
	
	public synchronized void decrease(){
//		if(0 == number){
		while(0 == number){
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		number--;
		System.out.println(number);
		notify();
	}
}
